package topo.console;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class ConsoleTextArea extends JTextArea implements ActionListener {
    private JPopupMenu consoleMenu;
    private JMenuItem copyItem;
    private JMenuItem selectAllItem;
    private JMenuItem clearSelectItem;
    private JMenuItem clearAllItem;
    private JMenuItem lockRollItem;
    private boolean lockRollBoolean = false;
    private final String LOCKROLL_YES = "滚动锁定";
    private final String LOCKROLL_NO = "滚动解锁";

    Font font = new Font("Courier", 0, 14);

    public ConsoleTextArea(InputStream[] inStreams) {
        for (int i = 0; i < inStreams.length; i++)
            startConsoleReaderThread(inStreams[i]);
    }

    public ConsoleTextArea() throws IOException {
        initConsoleArea();

        LoopedStreams ls = new LoopedStreams();

        PrintStream ps = new PrintStream(ls.getOutputStream());
        System.setOut(ps);
        System.setErr(ps);

        startConsoleReaderThread(ls.getInputStream());
    }

    private void initConsoleArea() {
        this.consoleMenu = new JPopupMenu();
        this.copyItem = new JMenuItem("复制");
        this.selectAllItem = new JMenuItem("全部选中");
        this.clearSelectItem = new JMenuItem("清除选中");
        this.clearAllItem = new JMenuItem("清除全部");
        this.lockRollItem = new JMenuItem("滚动锁定");

        this.consoleMenu.add(this.copyItem);
        this.consoleMenu.addSeparator();
        this.consoleMenu.add(this.selectAllItem);
        this.consoleMenu.add(this.clearSelectItem);
        this.consoleMenu.add(this.clearAllItem);
        this.consoleMenu.addSeparator();
        this.consoleMenu.add(this.lockRollItem);

        this.copyItem.addActionListener(this);
        this.selectAllItem.addActionListener(this);
        this.clearSelectItem.addActionListener(this);
        this.clearAllItem.addActionListener(this);
        this.lockRollItem.addActionListener(this);

        add(this.consoleMenu);
        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                if (e.getButton() == 3) {
                    ConsoleTextArea.this.copyItem.setEnabled(ConsoleTextArea.this.isCanCopy());
                    ConsoleTextArea.this.clearSelectItem.setEnabled(ConsoleTextArea.this.isCanCopy());
                    ConsoleTextArea.this.consoleMenu.show(ConsoleTextArea.this, e.getX(), e.getY());
                }
            }

            public void mouseEntered(MouseEvent mouseEvent) {
                ConsoleTextArea.this.setCursor(new Cursor(2));
            }
        });
        getCaret().addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                ConsoleTextArea.this.getCaret().setVisible(true);
            }
        });
        setEditable(false);
        setFont(this.font);
        setCaretColor(Color.RED);

        setTabSize(4);
    }

    public boolean isCanCopy() {
        boolean b = false;
        int start = getSelectionStart();
        int end = getSelectionEnd();
        if (start != end)
            b = true;
        return b;
    }

    private void startConsoleReaderThread(InputStream inStream) {
        final BufferedReader br = new BufferedReader(new InputStreamReader(inStream));
        new Thread(new Runnable() {
            public void run() {
                StringBuffer sb = new StringBuffer();
                try {
                    String s;
                    while ((s = br.readLine()) != null) {
                        sb.setLength(0);
                        ConsoleTextArea.this.append(s + '\n');
                        if (!ConsoleTextArea.this.lockRollBoolean)
                            ConsoleTextArea.this.setCaretPosition(ConsoleTextArea.this.getDocument().getLength());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public static void main(String[] args) {
        JFrame f = new JFrame("ConsoleTextArea测试");
        ConsoleTextArea consoleTextArea = null;
        try {
            consoleTextArea = new ConsoleTextArea();
        } catch (IOException e) {
            System.err.println("不能创建LoopedStreams：" + e);
        }

        consoleTextArea.setFont(Font.decode("monospaced"));
        f.getContentPane().add(new JScrollPane(consoleTextArea), "Center");
        f.setBounds(50, 50, 300, 300);
        f.setVisible(true);

        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent evt) {
                System.exit(0);
            }
        });
        startWriterTestThread("写操作线程 #1", System.err, 920, 50);
        startWriterTestThread("写操作线程 #2", System.out, 500, 50);
        startWriterTestThread("写操作线程 #3", System.out, 200, 50);
        startWriterTestThread("写操作线程 #4", System.out, 1000, 50);
        startWriterTestThread("写操作线程 #5", System.err, 850, 50);
    }

    private static void startWriterTestThread(final String name, final PrintStream ps, final int delay, int count) {
        new Thread(new Runnable() {
            public void run() {
                for (int i = 1; i <= this.val$count; i++) {
                    ps.println("***" + name + ", hello !, i=" + i);
                    try {
                        Thread.sleep(delay);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    public void actionPerformed(ActionEvent e) {
        String str = e.getActionCommand();
        if (str.equals(this.copyItem.getText())) {
            copy();
        } else if (str.equals(this.selectAllItem.getText())) {
            selectAll();
        } else if (str.equals(this.clearSelectItem.getText())) {
            replaceSelection(null);
        } else if (str.equals(this.clearAllItem.getText())) {
            setText("");
        } else if (str.equals("滚动锁定")) {
            this.lockRollBoolean = true;
            this.lockRollItem.setText("滚动解锁");
        } else if (str.equals("滚动解锁")) {
            this.lockRollBoolean = false;
            this.lockRollItem.setText("滚动锁定");
        }
    }
}